package com.fgc.util;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * JACKSON工具类
 *
 * @author 傅国成 2022/10/13 16:27
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JacksonUtil {
    public static final ObjectMapper         OBJECT_MAPPER = new ObjectMapper();
    public static final DefaultPrettyPrinter PRINTER       = new DefaultPrettyPrinter();

    /**
     * 初始化
     *
     * @author 傅国成 2022/10/13 16:28
     */
    static {
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        OBJECT_MAPPER.setSerializationInclusion(Include.NON_NULL);
        OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        OBJECT_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        // 配置四个空格的缩进
        DefaultPrettyPrinter.Indenter indenter = new DefaultIndenter("    ", DefaultIndenter.SYS_LF);
        PRINTER.indentObjectsWith(indenter); // Indent JSON objects
        PRINTER.indentArraysWith(indenter);  // Indent JSON arrays
        // LocalDateTime序列化
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        // LocalDateTime反序列化
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        OBJECT_MAPPER.registerModule(javaTimeModule);
    }

    /**
     * 转换为JSONSTRING
     *
     * @param obj
     *         源数据
     * @return java.lang.String
     * @author 傅国成 2022/10/13 16:28
     */
    public static String toJSONString(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 转换为JSONSTRING
     *
     * @param obj
     *         源数据
     * @param prettyFormat
     *         是否格式化
     * @return java.lang.String
     * @author 傅国成 2022/10/13 16:29
     */
    public static String toJSONString(Object obj, boolean prettyFormat) {
        try {
            if (prettyFormat) {
                return OBJECT_MAPPER.writer(PRINTER).writeValueAsString(obj);
            }
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * JSON字符串转换为Object
     *
     * @param str
     *         JSON字符串
     * @return java.lang.Object
     * @author 傅国成 2022/10/13 16:29
     */
    public static Object parse(String str) {
        return parseObject(str, Object.class);
    }

    /**
     * 数据转换为Map<String, Object>
     *
     * @param obj
     *         原始数据
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @author 傅国成 2023/3/30 10:35
     */
    public static Map<String, Object> parseObject(Object obj) {
        return parseObject(obj, Map.class);
    }

    /**
     * 数据转换为输入的类型
     *
     * @param obj
     *         原始数据
     * @param clazz
     *         期望的类型
     * @return T
     * @author 傅国成 2023/3/30 10:35
     */
    public static <T> T parseObject(Object obj, Class<T> clazz) {
        try {
            if (obj instanceof String) {
                return OBJECT_MAPPER.readValue((String) obj, clazz);
            }
            return OBJECT_MAPPER.readValue(toJSONString(obj), clazz);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 数据转换为List列表<字符串>
     *
     * @param obj
     *         原始数据
     * @return java.util.List<java.lang.String>
     * @author 傅国成 2023/3/30 10:35
     */
    public static List<String> parseList(Object obj) {
        return parseList(obj, String.class);
    }

    /**
     * 数据转换为List列表<期望的类型>
     *
     * @param obj
     *         原始数据
     * @param clazz
     *         期望的类型
     * @return java.util.List<T>
     * @author 傅国成 2023/3/30 10:35
     */
    public static <T> List<T> parseList(Object obj, Class<T> clazz) {
        try {
            JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(ArrayList.class, clazz);
            if (obj instanceof String) {
                return OBJECT_MAPPER.readValue((String) obj, javaType);
            }
            return OBJECT_MAPPER.readValue(toJSONString(obj), javaType);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 数据转换为Array数组<字符串>
     *
     * @param obj
     *         原始数据
     * @return java.lang.String[]
     * @author 傅国成 2023/3/30 10:35
     */
    public static String[] parseArray(Object obj) {
        return parseArray(obj, String.class);
    }

    /**
     * 数据转换为Array数组<期望的类型>
     *
     * @param obj
     *         原始数据
     * @param clazz
     *         期望的类型
     * @return T[]
     * @author 傅国成 2023/3/30 10:35
     */
    public static <T> T[] parseArray(Object obj, Class<T> clazz) {
        try {
            Class<T[]> arrayClass = (Class<T[]>) Class.forName("[L" + clazz.getName() + ";");
            if (obj instanceof String) {
                return OBJECT_MAPPER.readValue((String) obj, arrayClass);
            }
            return OBJECT_MAPPER.readValue(toJSONString(obj), arrayClass);
        } catch (JsonProcessingException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将数据转换为ObjectNode，失败返回null
     *
     * @param obj
     *         原始数据
     * @return com.fasterxml.jackson.databind.node.ObjectNode
     * @author 傅国成 2023/4/14 16:05
     */
    public static ObjectNode toObjectNode(Object obj) {
        JsonNode jsonNode = toJsonNode(obj);
        if (jsonNode != null && jsonNode.isObject()) {
            return (ObjectNode) jsonNode;
        }
        return null;
    }

    /**
     * 将数据转换为ArrayNode，失败返回null
     *
     * @param obj
     *         原始数据
     * @return com.fasterxml.jackson.databind.node.ArrayNode
     * @author 傅国成 2023/4/14 16:06
     */
    public static ArrayNode toArrayNode(Object obj) {
        JsonNode jsonNode = toJsonNode(obj);
        if (jsonNode != null && jsonNode.isArray()) {
            return (ArrayNode) jsonNode;
        }
        return null;
    }

    /**
     * 将JSON字符串转换为JsonNode，失败返回null
     *
     * @param obj
     *         原始数据
     * @return com.fasterxml.jackson.databind.JsonNode
     * @author 傅国成 2023/4/14 16:07
     */
    public static JsonNode toJsonNode(Object obj) {
        String json = obj instanceof String ? (String) obj : toJSONString(obj);
        if (json == null || "".equals(json.trim())) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readTree(json);
        } catch (JsonProcessingException e) {
            return null;
        }
    }

    /**
     * 获取JSON数据类型，为空返回JsonNodeType.NULL
     *
     * @param obj
     *         待测试JSON数据
     * @return com.fasterxml.jackson.databind.node.JsonNodeType
     * @author 傅国成 2023/4/14 16:51
     */
    public static JsonNodeType getJsonType(Object obj) {
        JsonNode jsonNode = toJsonNode(obj);
        if (jsonNode != null) {
            return jsonNode.getNodeType();
        }
        return JsonNodeType.NULL;
    }

    /**
     * 获取一个ObjectNode
     *
     * @return com.fasterxml.jackson.databind.node.ObjectNode
     * @author 傅国成 2022/10/13 16:35
     */
    public static ObjectNode getObjectNode() {
        return OBJECT_MAPPER.createObjectNode();
    }

    /**
     * 获取一个ArrayNode
     *
     * @return com.fasterxml.jackson.databind.node.ArrayNode
     * @author 傅国成 2022/10/13 16:36
     */
    public static ArrayNode getArrayNode() {
        return OBJECT_MAPPER.createArrayNode();
    }

    /**
     * 判断字符串是否是JSONObject
     *
     * @param json
     *         JSON字符串
     * @return boolean
     * @author 傅国成 2022/10/13 16:36
     */
    public static boolean isJsonObject(String json) {
        JsonNode jsonNode = toJsonNode(json);
        if (jsonNode == null) {
            return false;
        }
        return jsonNode.isObject();
    }

    /**
     * 判断字符串是否是JSON数组
     *
     * @param json
     *         JSON字符串
     * @return boolean
     * @author 傅国成 2022/10/13 16:37
     */
    public static boolean isJsonArray(String json) {
        JsonNode jsonNode = toJsonNode(json);
        if (jsonNode == null) {
            return false;
        }
        return jsonNode.isArray();
    }

    /**
     * 判断字符串是否是JSON数据
     *
     * @param json
     *         JSON字符串
     * @return boolean
     * @author 傅国成 2023/4/14 16:18
     */
    public static boolean isJson(String json) {
        JsonNode jsonNode = toJsonNode(json);
        if (jsonNode == null) {
            return false;
        }
        return jsonNode.isArray() || jsonNode.isObject();
    }
}
